# This target makes Kokoro complat that the Ninja version is too low.
#add_custom_target(all_xc7_iologic_vivado_diff_fasm)

# =============================================================================

function(xc7_iologic_design)
  # ~~~
  # XC7_IOLOGIC_DESIGN (
  #   BOARD <board>
  #   IOB_TYPE <iob_type>
  #   [USE_IDELAY <boolean>]
  #   [ILOGIC_MODE <ilogic_mode>]
  #   [OLOGIC_MODE <ologic_mode>]
  #   )
  # ~~~
  #
  # Generates a design that requires packing together an IOB+ILOGIC and
  # IOB+OLOGIC for the given IOB type and ILOGIC/OLOGIC mode of operation
  #
  # Allowed IOB_TYPE values are:
  #  - IBUF
  #  - IBUFDS
  #  - OBUF
  #  - OBUFT
  #  - OBUFDS
  #  - OBUFTDS
  #  - IOBUF
  #  - IOBUFDS
  #
  # Allowed ILOGIC operation modes:
  #  - NONE (or not given)
  #  - ISERDES
  #
  # Allowed OLOGIC operation modes:
  #  - NONE (or not given)
  #  - OSERDES
  #
  # TODO: Add support for IDDR and ODDR
  #
  # The BOARD parameter specifies the pinout variant. Please refer to the
  # generate.py script for the list of legal values.
  #
  # IMPORTANT: Please also note that designs generated by this function are
  # not meant to run on an actual hardware!
  #

    # Parse arguments
    set(OPTION_ARGS
    )
    set(ONE_VALUE_ARGS
        BOARD
        IOB_TYPE
        USE_IDELAY
        ILOGIC_MODE
        OLOGIC_MODE
    )
    set(MULTI_VALUE_ARGS
    )

    cmake_parse_arguments(
        XC7_IOLOGIC_DESIGN
        "${OPTION_ARGS}"
        "${ONE_VALUE_ARGS}"
        "${MULTI_VALUE_ARGS}"
        ${ARGN}
    )

    # Get args
    set(BOARD       ${XC7_IOLOGIC_DESIGN_BOARD})
    set(IOB_TYPE    ${XC7_IOLOGIC_DESIGN_IOB_TYPE})
    set(USE_IDELAY  ${XC7_IOLOGIC_DESIGN_USE_IDELAY})
    set(ILOGIC_MODE ${XC7_IOLOGIC_DESIGN_ILOGIC_MODE})
    set(OLOGIC_MODE ${XC7_IOLOGIC_DESIGN_OLOGIC_MODE})

    # Format the design name
    set(DESIGN iologic_${IOB_TYPE})
    if (${USE_IDELAY})
        set(DESIGN ${DESIGN}_IDELAY)
    endif()
    if (ILOGIC_MODE)
        set(DESIGN ${DESIGN}_${ILOGIC_MODE})
    endif()
    if (OLOGIC_MODE)
        set(DESIGN ${DESIGN}_${OLOGIC_MODE})
    endif()

    # Generate the design
    set(VERILOG_FILE ${DESIGN}.v)
    set(PCF_FILE ${DESIGN}.pcf)
    set(XDC_FILE ${DESIGN}.xdc)

    add_file_target(FILE ${VERILOG_FILE} GENERATED)
    add_file_target(FILE ${PCF_FILE} GENERATED)
    add_file_target(FILE ${XDC_FILE} GENERATED)

    set(IOLOGIC_OPTS "")
    if (${USE_IDELAY})
        set(IOLOGIC_OPTS ${IOLOGIC_OPTS} "--idelay")
    endif()
    if ("${ILOGIC_MODE}" STREQUAL "ISERDES")
        set(IOLOGIC_OPTS ${IOLOGIC_OPTS} "--iserdes")
    endif()
    if ("${OLOGIC_MODE}" STREQUAL "OSERDES")
        set(IOLOGIC_OPTS ${IOLOGIC_OPTS} "--oserdes")
    endif()

    add_custom_command(
        OUTPUT ${VERILOG_FILE} ${PCF_FILE} ${XDC_FILE}
        COMMAND ${PYTHON3} ${CMAKE_CURRENT_SOURCE_DIR}/generate.py
            --board ${BOARD}
            --iob ${IOB_TYPE}
            -o ${DESIGN}
            ${IOLOGIC_OPTS}
        DEPENDS ${PYTHON3} ${PYTHON3_TARGET} generate.py
        )

    # Add target
    add_fpga_target(
        NAME ${DESIGN}
        BOARD ${BOARD}
        INPUT_IO_FILE ${PCF_FILE}
        INPUT_XDC_FILE ${XDC_FILE}
        SOURCES ${VERILOG_FILE}
        EXPLICIT_ADD_FILE_TARGET
        )

    add_vivado_target(
        NAME ${DESIGN}_vivado
        PARENT_NAME ${DESIGN}
        XDC ${XDC_FILE}
        )

#    add_dependencies(all_xc7_iologic_vivado_diff_fasm ${DESIGN}_vivado_diff_fasm)

endfunction()

# =============================================================================

# Has to run on a chip with all IOBs bonded (eg. the "arty" board). Can be
# run on "basys3-bottom" once https://github.com/SymbiFlow/prjxray/issues/1329
# is fixed.
set(BOARD "arty-full")

# Generate all combinations
#
# Disabled for now. There are 32 combinations, most of them fail due to lack
# of correct pack-patterns.

#foreach(IOB_TYPE IBUF IBUFDS)
#    foreach(USE_IDELAY 0 1)
#        foreach(USE_ISERDES 0 1)
#            xc7_iologic_design(${BOARD} ${IOB_TYPE} ${USE_IDELAY} ${USE_ISERDES} 0)
#        endforeach()
#    endforeach()
#endforeach()
#
#foreach(IOB_TYPE OBUF OBUFT OBUFDS OBUFTDS)
#    foreach(USE_OSERDES 0 1)
#        xc7_iologic_design(${BOARD} ${IOB_TYPE} 0 0 ${USE_OSERDES})
#    endforeach()
#endforeach()
#
#foreach(IOB_TYPE IOBUF IOBUFDS)
#    foreach(USE_IDELAY 0 1)
#        foreach(USE_ISERDES 0 1)
#            foreach(USE_OSERDES 0 1)
#                xc7_iologic_design(${BOARD} ${IOB_TYPE} ${USE_IDELAY} ${USE_ISERDES} ${USE_OSERDES})
#            endforeach()
#        endforeach()
#    endforeach()
#endforeach()


# These tests succeed:

# Inputs
xc7_iologic_design(BOARD ${BOARD} IOB_TYPE IBUF    USE_IDELAY 0)

# Inouts
xc7_iologic_design(BOARD ${BOARD} IOB_TYPE IOBUF   USE_IDELAY 0)
xc7_iologic_design(BOARD ${BOARD} IOB_TYPE IOBUF   USE_IDELAY 0 ILOGIC_MODE ISERDES OLOGIC_MODE OSERDES)
xc7_iologic_design(BOARD ${BOARD} IOB_TYPE IOBUF   USE_IDELAY 1 ILOGIC_MODE ISERDES OLOGIC_MODE OSERDES)
xc7_iologic_design(BOARD ${BOARD} IOB_TYPE IOBUF   USE_IDELAY 0                     OLOGIC_MODE OSERDES)

xc7_iologic_design(BOARD ${BOARD} IOB_TYPE IOBUFDS USE_IDELAY 0)
xc7_iologic_design(BOARD ${BOARD} IOB_TYPE IOBUFDS USE_IDELAY 0                     OLOGIC_MODE OSERDES)
xc7_iologic_design(BOARD ${BOARD} IOB_TYPE IOBUFDS USE_IDELAY 0 ILOGIC_MODE ISERDES)
xc7_iologic_design(BOARD ${BOARD} IOB_TYPE IOBUFDS USE_IDELAY 0 ILOGIC_MODE ISERDES OLOGIC_MODE OSERDES)
xc7_iologic_design(BOARD ${BOARD} IOB_TYPE IOBUFDS USE_IDELAY 1 ILOGIC_MODE ISERDES)
xc7_iologic_design(BOARD ${BOARD} IOB_TYPE IOBUFDS USE_IDELAY 1 ILOGIC_MODE ISERDES OLOGIC_MODE OSERDES)

# Outputs
xc7_iologic_design(BOARD ${BOARD} IOB_TYPE OBUF)
xc7_iologic_design(BOARD ${BOARD} IOB_TYPE OBUF    OLOGIC_MODE OSERDES)
xc7_iologic_design(BOARD ${BOARD} IOB_TYPE OBUFDS)
xc7_iologic_design(BOARD ${BOARD} IOB_TYPE OBUFDS  OLOGIC_MODE OSERDES)
xc7_iologic_design(BOARD ${BOARD} IOB_TYPE OBUFTDS)
xc7_iologic_design(BOARD ${BOARD} IOB_TYPE OBUFTDS OLOGIC_MODE OSERDES)


